// SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
// SPDX-License-Identifier: Apache-2.0

package roadmap_dao

import (
	"context"

	"gitcode.com/lvupclub/lvup-api/dao/common"
	"gitcode.com/lvupclub/proto-gen-go.git/src/roadmap_data_state_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/roadmap_data_type_api"
	"go.mongodb.org/mongo-driver/v2/bson"
	"go.mongodb.org/mongo-driver/v2/mongo"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/types/known/anypb"
)

type NodeStateInfoDbItem struct {
	StateId      string `bson:"_id"`
	RoadmapId    string `bson:"roadmapId"`
	MemberUserId string `bson:"memberUserId"`
	NodeId       string `bson:"nodeId"`
	StateData    []byte `bson:"stateData"`
	TimeStamp    int64  `bson:"timeStamp"`
}

func (item *NodeStateInfoDbItem) ToNodeStateInfo() (*roadmap_data_state_api.NodeStateInfo, error) {
	state := &anypb.Any{}
	err := proto.Unmarshal(item.StateData, state)
	if err != nil {
		state, err = anypb.New(&roadmap_data_type_api.UnknownState{})
		if err != nil {
			return nil, err
		}
	}
	return &roadmap_data_state_api.NodeStateInfo{
		StateId:      item.StateId,
		NodeId:       item.NodeId,
		MemberUserId: item.MemberUserId,
		State:        state,
		TimeStamp:    item.TimeStamp,
	}, nil
}

type _NodeStateInfoDao struct {
	mc *mongo.Collection
}

func newNodeStateInfoDao(db *mongo.Database) (*_NodeStateInfoDao, error) {
	mc := db.Collection(common.DB_NS_ROADMAP + "node_state")
	_, err := mc.Indexes().CreateOne(context.Background(), mongo.IndexModel{
		Keys: bson.D{{"roadmapId", 1}, {"memberUserId", 1}},
	})
	if err != nil {
		return nil, err
	}
	return &_NodeStateInfoDao{mc: mc}, nil
}

func (db *_NodeStateInfoDao) Insert(ctx context.Context, dbItem *NodeStateInfoDbItem) error {
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_NodeStateInfoDao) Exist(ctx context.Context, stateId, roadmapId, nodeId, memberUserId string) (bool, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"_id": stateId, "roadmapId": roadmapId, "nodeId": nodeId, "memberUserId": memberUserId})
	return count > 0, err
}

func (db *_NodeStateInfoDao) Get(ctx context.Context, stateId, roadmapId, nodeId, memberUserId string) (*NodeStateInfoDbItem, error) {
	retItem := &NodeStateInfoDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"_id": stateId, "roadmapId": roadmapId, "nodeId": nodeId, "memberUserId": memberUserId}).Decode(retItem)
	return retItem, err
}

func (db *_NodeStateInfoDao) Remove(ctx context.Context, stateId, roadmapId, nodeId, memberUserId string) error {
	_, err := db.mc.DeleteOne(ctx, bson.M{"_id": stateId, "roadmapId": roadmapId, "nodeId": nodeId, "memberUserId": memberUserId})
	return err
}

func (db *_NodeStateInfoDao) List(ctx context.Context, roadmapId, memberUserId string) ([]*NodeStateInfoDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{"roadmapId": roadmapId, "memberUserId": memberUserId})
	if err != nil {
		return nil, err
	}
	retList := []*NodeStateInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}
